`timescale 1ns/1ps
module decoder(
  input [31:0] comb_decode_inst,
  output wire [25:0] comb_decode
);
  reg we_reg, npc_sel;                //寄存器写使能，PC写回选择
  reg [1:0] alu_asel, alu_bsel;       //alu_a和_b端口选择
  reg [3:0] alu_op;                   //运算操作
  reg we_mem;                         //内存写使能
  reg [2:0] immgen_op;                //立即数选择
  reg [2:0] bralu_op;                 //分支计算操作
  reg [1:0] wb_sel;                   //写回数据选择
  reg [2:0] memdata_width;            //访问宽度
  wire [6:0] op_code;
  wire [2:0] func3;
  reg csr_we;
  reg rs1_use;
  reg rs2_use;
  reg re_mem;
  assign op_code=comb_decode_inst[6:0];
  assign func3=comb_decode_inst[14:12];

always @(*) begin
    we_reg = 0;
    alu_asel = 0;
    alu_bsel = 0;
    alu_op = 0;
    we_mem=0;
    npc_sel=0;
    immgen_op=0;
    bralu_op=0;
    wb_sel=0;
    memdata_width=0;
    rs1_use = 0;
    rs2_use = 0;
    re_mem = 0;
  case (op_code)
      7'b0001101:                                         //li
      begin
        we_reg = 1'b1;       
        alu_bsel=2'b10;
        immgen_op=3'b100;
        wb_sel=2'b01;
        rs1_use = 1'b0;
        rs2_use = 1'b0;
        re_mem = 1'b0;
      end
      7'b0110111:                                        //U lui指令
      begin 
        we_reg = 1'b1;       
        alu_bsel=2'b10;
        immgen_op=3'b100;
        wb_sel=2'b01;
        rs1_use = 1'b0;
        rs2_use = 1'b0;
        re_mem = 1'b0;
        end 
      7'b0010111:                                        //U auipc指令
      begin  
        we_reg=1'b1; 
        alu_asel=2'b10;
        alu_bsel=2'b10; 
        immgen_op=3'b100;
        wb_sel=2'b01;
        rs1_use = 1'b0;
        rs2_use = 1'b0;
        re_mem = 1'b0;
        end
      7'b0010011:                                        //I型，addi, slti, sltiu, xori, ori, andi, slli, srli, srai
      begin //addi x0,0  000011001000000000100110
      //  assign comb_decode={rs2_use,rs1_use,we_reg, we_mem, npc_sel, immgen_op, alu_op, bralu_op, alu_asel, alu_bsel, wb_sel, memdata_width};
        alu_asel=2'b01;
        alu_bsel=2'b10;
        we_reg=1; 
        immgen_op=3'b001;
        wb_sel=2'b01;
        rs1_use = 1'b1;
        rs2_use = 1'b0;
        re_mem = 1'b0;
        case(func3)
          3'b000:alu_op=4'b0000;//addi
          3'b001:alu_op=4'b0111;//slli
          3'b010:alu_op=4'b0101;//slti
          3'b011:alu_op=4'b0110;//sltiu
          3'b100:alu_op=4'b0100;//xori
          3'b101:
            if(comb_decode_inst[31:26]==0) alu_op=4'b1000;//srli
            else begin 
              alu_op=4'b1001;//srai
            immgen_op=3'b110;
            end
          3'b110:alu_op=4'b0011;//ori
          3'b111:alu_op=4'b0010;//andi
          default:alu_op=4'b0000;
        endcase
      end 
      7'b0011011://addiw等i型拓展
       begin
        alu_asel=2'b01;
        alu_bsel=2'b10;
        we_reg=1; 
        immgen_op=3'b001; 
        wb_sel=2'b01;
        rs1_use = 1'b1;
        rs2_use = 1'b0;
        re_mem = 1'b0;
         case(func3)
           3'b000:alu_op=4'b1010;//addiw
           3'b001:alu_op=4'b1100;//slliw
           3'b101:
            if(comb_decode_inst[31:25]==0) alu_op=4'b1101;//srliw
            else begin alu_op=4'b1110;//sraiw
            immgen_op=3'b111; end
          default:alu_op=0;
       endcase
       end
      7'b0000011: //load型
      begin
        case(func3)
          3'b000: memdata_width= 3'b100; //lb
          3'b001: memdata_width= 3'b011; //lh
          3'b010: memdata_width= 3'b010; //lw
          3'b011: memdata_width= 3'b001; //double word
          3'b100: memdata_width= 3'b111; //lbu,unsigned byte
          3'b101: memdata_width= 3'b110; //lhu,unsigned half word 
          3'b110: memdata_width= 3'b101; //unsigned word            
          default: memdata_width= 3'b000;
        endcase  
        we_reg=1; 
        alu_asel=2'b01;
        alu_bsel=2'b10; 
        immgen_op=3'b001;
        wb_sel=2'b10;
        rs1_use = 1'b1;
        rs2_use = 1'b0;
        re_mem = 1'b1;
      end
      7'b0110011: //R型，add, sub, sll, slt, sltu, xor, srl, sra, or, and
      begin
        case(func3)
          3'b000:
            if(comb_decode_inst[31:25]==0) alu_op=4'b0000;//add
            else alu_op=4'b0001;//sub
          3'b001:alu_op=4'b0111;//sll
          3'b010:alu_op=4'b0101;//slt
          3'b011:alu_op=4'b0110;//sltu
          3'b100:alu_op=4'b0100;//xor
          3'b101:
            if(comb_decode_inst[31:25]==0) alu_op=4'b1000;//srl
            else alu_op=4'b1001;//sra
          3'b110:alu_op=4'b0011;//or
          3'b111:alu_op=4'b0010;//and
          default:alu_op=4'b0;
        endcase
        we_reg=1'b1;
        alu_asel=2'b01;
        alu_bsel=2'b01;
        wb_sel=2'b01;
        rs1_use = 1'b1;
        rs2_use = 1'b1;
        re_mem = 1'b0;
      end
      7'b0111011://addw等r型拓展
       begin
         case(func3)
          3'b000:
            if(comb_decode_inst[31:25]==0) alu_op=4'b1010;//addw
            else alu_op=4'b1011;//subw
          3'b001:alu_op=4'b1100;//sllw
          3'b101:
            if(comb_decode_inst[31:25]==0) alu_op=4'b1101;//srlw
            else alu_op=4'b1110;//sraw
          default:alu_op=0;
        endcase
        we_reg=1'b1;
        alu_asel=2'b01;
        alu_bsel=2'b01;
        wb_sel=2'b01;
        rs1_use = 1'b1;
        rs2_use = 1'b1;
        re_mem = 1'b0;
       end 
      7'b0100011://S型
      begin
        case(func3)
          3'b000: memdata_width= 3'b100;//sb
          3'b001: memdata_width= 3'b011;//sh
          3'b010: memdata_width= 3'b010;//sw
          3'b011: memdata_width= 3'b001;//sd
          default: memdata_width=3'b000;
        endcase  
        alu_asel=2'b01;
        alu_bsel=2'b10; 
        we_mem=1'b1;
        immgen_op=3'b010;
        rs1_use = 1'b1;
        rs2_use = 1'b1;
        re_mem = 1'b0;
      end
     7'b1100011: //B型，beq, bne, blt, bge, bltu, bgeu
      begin
        case(func3)
          3'b000: bralu_op=3'b001;//beq
          3'b001: bralu_op=3'b010;//bne
          3'b100: bralu_op=3'b011;//blt
          3'b101: bralu_op=3'b100;//bge
          3'b110: bralu_op=3'b101;//bltu
          3'b111: bralu_op=3'b110;//bgeu
          default: bralu_op=3'b000;
        endcase
        alu_asel=2'b10;
        alu_bsel=2'b10;
        npc_sel=1;
        immgen_op=3'b011;
        wb_sel=2'b01;
        rs1_use = 1'b1;
        rs2_use = 1'b1;
        re_mem = 1'b0;
      end
      7'b1100111: //jalr指令
      begin
        we_reg=1; 
        npc_sel=1;
        immgen_op=3'b001;
        alu_asel=2'b01;
        alu_bsel=2'b10;
        wb_sel=2'b11;
        rs1_use = 1'b1;
        rs2_use = 1'b0;
        re_mem = 1'b0;
        end
      7'b1101111: //jal指令
      begin  
        we_reg = 1'b1; 
        alu_asel=2'b10;
        alu_bsel=2'b10;
        npc_sel=1;
        immgen_op=3'b101;
        wb_sel=2'b11;
        rs1_use = 1'b0;
        rs2_use = 1'b0;
        re_mem = 1'b0;
        end
      7'b1110011://csr
       begin
         case(func3)
          3'b001:                  //CSRRW
          begin
            we_reg = 1'b1;
            immgen_op = 3'b000;
            alu_asel=2'b01;
            alu_bsel=2'b00;        // 0
            wb_sel = 2'b00;        // 00 写回 WB_csr_val(旧的csr值)  01 写回 WB_alu_res
            // csr_wb_sel = 2'b01;    // 00 写回 WB_csr_res   01写回 WB_CSR_RES  10写回wb_csr_val
            rs1_use = 1'b1;
            // rs2_use = 1'b0;
            // re_mem = 1'b0;
          end
          3'b010:                  //CSRRS
          begin
            we_reg = 1'b1;
            immgen_op = 3'b000;
            alu_asel = 2'b01; // register
            alu_bsel = 2'b00; // 0
            alu_op = 4'b0000; // 0 + register
            wb_sel = 2'b00;
            rs1_use = 1'b1;
          end
          3'b011:                  //CSRRC
          begin
            we_reg = 1'b1;
            immgen_op = 3'b000;
            alu_asel = 2'b01; // register
            alu_bsel = 2'b00; // 0
            alu_op = 4'b0000; // 0 + register
            wb_sel = 2'b01;
            rs1_use = 1'b1;
          end
          3'b101:                  //CSRRWI
          begin
            we_reg = 1'b1;
            immgen_op = 3'b111;
            alu_asel = 2'b00; //0
            alu_bsel = 2'b10; // imm
            wb_sel = 2'b01;
            alu_op = 4'b0000;
          end
          3'b110:                  //CSRRSI
          begin
            we_reg = 1'b1;
            immgen_op = 3'b111;
            alu_asel = 2'b00;
            alu_bsel = 2'b10;
            wb_sel = 2'b01;
            alu_op = 4'b0000;
          end
          3'b111:                  //CSRRCI
          begin
            we_reg = 1'b1;
            immgen_op = 3'b111;
            alu_asel = 2'b00;
            alu_bsel = 2'b10;
            wb_sel = 2'b01;
            alu_op = 4'b0000;
          end
          default:alu_op=0;
        endcase
       end 
     default: alu_op=0;
    endcase
  end
  assign csr_we = (op_code == 7'b1110011 && comb_decode_inst[19:15] != 5'b0) ? 1 : 0;
  assign comb_decode={csr_we,re_mem,rs2_use,rs1_use,we_reg, we_mem, npc_sel, immgen_op, alu_op, bralu_op, alu_asel, alu_bsel, wb_sel, memdata_width};
endmodule
